package Model

import (
	"database/sql"
	"errors"
	_ "github.com/go-sql-driver/mysql"
	"strconv"
)

type DbInterface interface {
	Open(host string, port int, dbName string, user string, pass string) (*(sql.DB), error) //打开一个连接
	Close() error                                                                           //关闭一个连接
	Clear() (bool, error)                                                                   //释放一个连接
	Query(sql string, args ...interface{}) ([]map[string]interface{}, error)                //事务无关的查询
	Execute(sql string, args ...interface{}) (sql.Result, error)                            //事务无关的更新
	Begin() (*(sql.Tx), error)                                                              //事物相关的启动
	Commit(tx *(sql.Tx)) error                                                              //事务相关的提交
	Rollback(tx *(sql.Tx)) error                                                            //事务相关的回滚
	TxExecute(tx *(sql.Tx), sql string, args ...interface{}) (sql.Result, error)            //事务相关的更新
}

type MysqlDb struct {
	host       string
	port       int
	db_name    string
	user       string
	pass       string
	connection *sql.DB
}

func (mysqlDb *MysqlDb) Open(host string, port int, dbName string, user string, pass string) (*(sql.DB), error) {
	//初始化
	var connection *(sql.DB) = nil
	var openErr error = nil
	//打开数据库
	if (dbName != "") && (dbName != "*") {
		connection, openErr = sql.Open("mysql", user+":"+pass+"@("+host+":"+strconv.Itoa(port)+")/"+dbName)
	} else {
		connection, openErr = sql.Open("mysql", user+":"+pass+"@("+host+":"+strconv.Itoa(port)+")")
	}
	if openErr != nil {
		return nil, openErr
	}
	//连接数据库
	var pingErr = connection.Ping()
	if pingErr != nil {
		var closeErr = connection.Close()
		if closeErr != nil {
			return nil, closeErr
		}
		return nil, pingErr
	}
	//初始化对象属性
	mysqlDb.host = host
	mysqlDb.port = port
	mysqlDb.db_name = dbName
	mysqlDb.user = user
	mysqlDb.pass = pass
	mysqlDb.connection = connection
	return mysqlDb.connection, nil
}

func (mysqlDb *MysqlDb) Ping() (*(sql.DB), error) {
	if mysqlDb == nil {
		return nil, errors.New("重新进行数据库连接时，发现数据库对象句柄是空的")
	}
	if mysqlDb.connection == nil {
		return nil, errors.New("重新进行数据库连接时，发现数据库连接对象句柄是空的")
	}
	//连接数据库
	var pingErr = mysqlDb.connection.Ping()
	if pingErr != nil {
		var closeErr = mysqlDb.connection.Close()
		if closeErr != nil {
			return nil, closeErr
		}
		return nil, pingErr
	}
	return mysqlDb.connection, nil
}

func (mysqlDb *MysqlDb) Close() error {
	if mysqlDb == nil {
		return errors.New("关闭数据库连接时，发现数据库对象句柄是空的")
	}
	if mysqlDb.connection == nil {
		return errors.New("关闭数据库连接时，发现数据库连接对象句柄是空的")
	}
	err := mysqlDb.connection.Close()
	//
	return err
}

func (mysqlDb *MysqlDb) Clear() (bool, error) {
	if mysqlDb == nil {
		return false, errors.New("释放数据库连接时，发现数据库对象句柄是空的")
	}
	if mysqlDb.connection != nil {
		err := mysqlDb.connection.Close()
		if err != nil {
			return false, err
		}
		mysqlDb.connection = nil
	}
	//
	return true, nil
}

func (mysqlDb *MysqlDb) Query(sql string, args ...interface{}) ([]map[string]interface{}, error) {
	if mysqlDb == nil {
		return nil, errors.New("执行查询数据时，发现数据库对象句柄是空的")
	}
	if mysqlDb.connection == nil {
		return nil, errors.New("执行查询数据时，发现数据库连接对象句柄是空的")
	}
	//初始化返回信息（元素为map的动态数组（切片））
	var maps []map[string]interface{} = make([]map[string]interface{}, 0)
	var mapsIndex uint64 = 0
	//
	rows, err := mysqlDb.connection.Query(sql, args...)
	//查询失败
	if err != nil {
		return maps, err
	}
	fieldNames, err := rows.Columns()
	if err != nil {
		return maps, err
	}
	fieldNamesLen := len(fieldNames)
	//生成返回信息
	for rows.Next() {
		tmpMap := make(map[string]interface{})
		if err := rows.GjScan(fieldNames, &tmpMap, fieldNamesLen); err != nil {
			return maps, err
		}
		maps = append(maps, tmpMap)
		//
		mapsIndex++
	}
	//
	if err := rows.Err(); err != nil {
		return maps, err
	}
	return maps, nil
}

func (mysqlDb *MysqlDb) Execute(sql string, args ...interface{}) (sql.Result, error) {
	if mysqlDb == nil {
		return nil, errors.New("执行数据更新时，发现数据库对象句柄是空的")
	}
	if mysqlDb.connection == nil {
		return nil, errors.New("执行数据更新时，发现数据库连接对象句柄是空的")
	}
	//
	result, err := mysqlDb.connection.Exec(sql, args...)
	return result, err
}

func (mysqlDb *MysqlDb) Begin() (*(sql.Tx), error) {
	if mysqlDb == nil {
		return nil, errors.New("启动数据库事务时，发现数据库对象句柄是空的")
	}
	if mysqlDb.connection == nil {
		return nil, errors.New("启动数据库事务时，发现数据库连接对象句柄是空的")
	}
	tx, err := mysqlDb.connection.Begin()
	if err != nil {
		return nil, err
	}
	return tx, nil
}

func (mysqlDb *MysqlDb) Commit(tx *(sql.Tx)) error {
	if mysqlDb == nil {
		return errors.New("提交数据库事务时，发现数据库对象句柄是空的")
	}
	if mysqlDb.connection == nil {
		return errors.New("提交数据库事务时，发现数据库连接对象句柄是空的")
	}
	err := tx.Commit()
	if err != nil {
		return err
	}
	return nil
}

func (mysqlDb *MysqlDb) Rollback(tx *(sql.Tx)) error {
	if mysqlDb == nil {
		return errors.New("回滚数据库事务时，发现数据库对象句柄是空的")
	}
	if mysqlDb.connection == nil {
		return errors.New("回滚数据库事务时，发现数据库连接对象句柄是空的")
	}
	err := tx.Rollback()
	if err != nil {
		return err
	}
	return nil
}

func (mysqlDb *MysqlDb) TxExecute(tx *(sql.Tx), sql string, args ...interface{}) (sql.Result, error) {
	if mysqlDb == nil {
		return nil, errors.New("执行数据更新时，发现数据库对象句柄是空的")
	}
	if mysqlDb.connection == nil {
		return nil, errors.New("执行数据更新时，发现数据库连接对象句柄是空的")
	}
	//
	result, err := tx.Exec(sql, args...)
	return result, err
}
